/**
 * 
 */
package dms.repository.impl;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.Map.Entry;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.hibernate.Transaction;
import org.hibernate.classic.Session;
import org.hibernate.persister.entity.Loadable;

import dms.model.Building;
import dms.model.Campus;
import dms.model.form.FoundNotice;
import dms.model.form.LostNotice;
import dms.model.form.Notice;
import dms.model.util.FindUtil;
import dms.model.util.PageIterator;
import dms.repository.NoticeRepository;
import dms.util.HibernateUtil;

/**
 * @author 李健
 *
 */
public class NoticeRepositoryHibernate implements NoticeRepository {

	private static final Log log = LogFactory.getLog(NoticeRepositoryHibernate.class);
	
	/* (non-Javadoc)
	 * @see dms.repository.NoticeRepository#createNotice(dms.model.form.Notice)
	 */
	@Override
	public Notice createNotice(Notice notice) throws Exception {
		Session session = null;
		Transaction tx = null;
		
		try {
			
			session = HibernateUtil.getSessionFactory().getCurrentSession();
			tx = session.beginTransaction();
			
			session.save(notice);
			
			tx.commit();
		} catch (Exception e) {
			log.error(e.getMessage());
			if (tx != null) {
				tx.rollback();
			}
			throw e;
		} finally {
			if (session != null) {
				if (session.isOpen()) {
					session.close();
				}
			}
		}
		return notice;
	}

	/* (non-Javadoc)
	 * @see dms.repository.NoticeRepository#deleteNoticeById(java.lang.Long)
	 */
	@Override
	public void deleteNoticeById(Long id) throws Exception {
		Session session = null;
		Transaction tx = null;
		Notice notice = null;
		
		try {
			
			session = HibernateUtil.getSessionFactory().getCurrentSession();
			tx = session.beginTransaction();
			
			notice = (Notice) session.load(Notice.class, id);
			session.delete(notice);
			
			tx.commit();
		} catch (Exception e) {
			log.error(e.getMessage());
			if (tx != null) {
				tx.rollback();
			}
			throw e;
		} finally {
			if (session != null) {
				if (session.isOpen()) {
					session.close();
				}
			}
		}
		

	}

	/* (non-Javadoc)
	 * @see dms.repository.NoticeRepository#deleteNotices(java.util.List)
	 */
	@Override
	public void deleteNotices(List<Long> ids) throws Exception {
		Session session = null;
		Transaction tx = null;
		
		String deleteQuery = "delete from Notice n  where n.id in (:ids)";
		try {
			
			session = HibernateUtil.getSessionFactory().getCurrentSession();
			tx = session.beginTransaction();
			
			session.createQuery(deleteQuery)
				   .setParameterList("ids", ids)
				   .executeUpdate();
			
			tx.commit();
		} catch (Exception e) {
			log.error(e.getMessage());
			if (tx != null) {
				tx.rollback();
			}
			throw e;
		} finally {
			if (session != null) {
				if (session.isOpen()) {
					session.close();
				}
			}
		}
		
	}

	/* (non-Javadoc)
	 * @see dms.repository.NoticeRepository#deleteNotices(java.lang.Long[])
	 */
	@Override
	public void deleteNotices(Long[] ids) throws Exception {
		deleteNotices(Arrays.asList(ids));

	}

	/* (non-Javadoc)
	 * @see dms.repository.NoticeRepository#findAllFoundNotice(int, int, java.util.Date, java.util.Date, java.lang.Boolean)
	 */
	@Override
	public PageIterator<Notice> findAllFoundNotice(int start, int count, String query,
			Date fromDate, Date toDate, Boolean applied) {
		return find(start, count, null, query, fromDate, toDate, 'F', applied);
	}

	/* (non-Javadoc)
	 * @see dms.repository.NoticeRepository#findAllLostNotice(int, int, java.util.Date, java.util.Date, java.lang.Boolean)
	 */
	@Override
	public PageIterator<Notice> findAllLostNotice(int start, int count, String query,
			Date fromDate, Date toDate, Boolean applied) {
		return find(start, count, null, query, fromDate, toDate, 'L', applied);
	}

	/* (non-Javadoc)
	 * @see dms.repository.NoticeRepository#findFoundNoticeByBuilding(int, int, dms.model.Building, java.util.Date, java.util.Date, java.lang.Boolean)
	 */
	@Override
	public PageIterator<Notice> findFoundNoticeByBuilding(int start,
			int count, Building building, Date fromDate, Date toDate,
			Boolean applied) {
		Map keyValue = new HashMap();
		keyValue.put("building", building);
		return find(start, count, keyValue, null, fromDate, toDate, 'F', applied);
	}

	/* (non-Javadoc)
	 * @see dms.repository.NoticeRepository#findFoundNoticeByBuildingAndQuery(int, int, dms.model.Building, java.lang.String, java.util.Date, java.util.Date, java.lang.Boolean)
	 */
	@Override
	public PageIterator<Notice> findFoundNoticeByBuildingAndQuery(
			int start, int count, Building building, String query,
			Date fromDate, Date toDate, Boolean applied) {
		Map keyValue = new HashMap();
		keyValue.put("building", building);
		return find(start, count, keyValue, query, fromDate, toDate, 'F', applied);
	}

	/* (non-Javadoc)
	 * @see dms.repository.NoticeRepository#findFoundNoticeByCampus(int, int, dms.model.Campus, java.util.Date, java.util.Date, java.lang.Boolean)
	 */
	@Override
	public PageIterator<Notice> findFoundNoticeByCampus(int start,
			int count, Campus campus, Date fromDate, Date toDate,
			Boolean applied) {
		Map keyValue = new HashMap();
		keyValue.put("building.campus", campus);
		return find(start, count, keyValue, null, fromDate, toDate, 'F', applied);
	}

	/* (non-Javadoc)
	 * @see dms.repository.NoticeRepository#findFoundNoticeByCampusAndQuery(int, int, dms.model.Campus, java.lang.String, java.util.Date, java.util.Date, java.lang.Boolean)
	 */
	@Override
	public PageIterator<Notice> findFoundNoticeByCampusAndQuery(int start,
			int count, Campus campus, String query, Date fromDate, Date toDate,
			Boolean applied) {
		Map keyValue = new HashMap();
		keyValue.put("building.campus", campus);
		return find(start, count, keyValue, query, fromDate, toDate, 'F', applied); 
	}

	/* (non-Javadoc)
	 * @see dms.repository.NoticeRepository#findLostNoticeByBuilding(int, int, dms.model.Building, java.util.Date, java.util.Date, java.lang.Boolean)
	 */
	@Override
	public PageIterator<Notice> findLostNoticeByBuilding(int start,
			int count, Building building, Date fromDate, Date toDate,
			Boolean applied) {
		Map keyValue = new HashMap();
		keyValue.put("building", building);
		return find(start, count, keyValue, null, fromDate, toDate, 'L', applied);
	}

	/* (non-Javadoc)
	 * @see dms.repository.NoticeRepository#findLostNoticeByBuildingAndQuery(int, int, dms.model.Building, java.lang.String, java.util.Date, java.util.Date, java.lang.Boolean)
	 */
	@Override
	public PageIterator<Notice> findLostNoticeByBuildingAndQuery(int start,
			int count, Building building, String query, Date fromDate,
			Date toDate, Boolean applied) {
		Map keyValue = new HashMap();
		keyValue.put("building", building);
		return find(start, count, keyValue, query, fromDate, toDate, 'L', applied);
	}

	/* (non-Javadoc)
	 * @see dms.repository.NoticeRepository#findLostNoticeByCampus(int, int, dms.model.Campus, java.util.Date, java.util.Date, java.lang.Boolean)
	 */
	@Override
	public PageIterator<Notice> findLostNoticeByCampus(int start,
			int count, Campus campus, Date fromDate, Date toDate,
			Boolean applied) {
		Map keyValue = new HashMap();
		keyValue.put("building.campus", campus);
		return find(start, count, keyValue, null, fromDate, toDate, 'L', applied);
	}

	/* (non-Javadoc)
	 * @see dms.repository.NoticeRepository#findLostNoticeByCampusAndQuery(int, int, dms.model.Campus, java.lang.String, java.util.Date, java.util.Date, java.lang.Boolean)
	 */
	@Override
	public PageIterator<Notice> findLostNoticeByCampusAndQuery(int start,
			int count, Campus campus, String query, Date fromDate, Date toDate,
			Boolean applied) {
		Map keyValue = new HashMap();
		keyValue.put("building.campus", campus);
		return find(start, count, keyValue, query, fromDate, toDate, 'L', applied); 
	}

	/* (non-Javadoc)
	 * @see dms.repository.NoticeRepository#updateNotice(dms.model.form.Notice)
	 */
	@Override
	public Notice updateNotice(Notice notice) throws Exception {
		Session session = null;
		Transaction tx = null;
		
		try {
			
			session = HibernateUtil.getSessionFactory().getCurrentSession();
			tx = session.beginTransaction();
			
			session.merge(notice);
			
			tx.commit();
		} catch (Exception e) {
			log.error(e.getMessage());
			if (tx != null) {
				tx.rollback();
			}
			throw e;
		} finally {
			if (session != null) {
				if (session.isOpen()) {
					session.close();
				}
			}
		}
		return notice;
	}

	/**
	 * 
	 * @param start
	 * @param count
	 * @param keyValue
	 * @param query
	 * @param fromDate
	 * @param toDate
	 * @param type
	 * @param applied
	 * @return
	 */
	private PageIterator<Notice> find(int start, 
												int count, 
												Map keyValue, 
												String query, 
												Date fromDate,
												Date toDate,
												Character type,
												Boolean applied) {
		Session session = null;
		Transaction tx = null;
		List<Notice> list = null;
		PageIterator<Notice> iter = null;
		Long allCount = null;		
		
		StringBuilder countQuery = new StringBuilder("select count(*) from ");
		StringBuilder findQuery = new StringBuilder("select n from  ");
		StringBuilder conditionQuery = new StringBuilder();
		Collection params = new ArrayList();
		
		if (type != null) {
			if (type.equals('L') || type.equals('l')) {
				conditionQuery.append(" LostNotice  n where ");
				if (query != null) {
					conditionQuery
							.append("  (n.lostPerson like  ? or n.description like ?) and ");
					params.add("%" + query + "%");
					params.add("%" + query + "%");
				}
			} else if (type.equals('F') || type.equals('f')) {
				conditionQuery.append(" FoundNotice n  where ");
				if (query != null) {
					conditionQuery
							.append("  ( n.foundPerson like ? or n.description like ?) and ");
					params.add("%" + query + "%");
					params.add("%" + query + "%");
				}
			} else {
				conditionQuery.append(" Notice n where ");
			}

		} else {
			conditionQuery.append(" Notice n where ");
		}
		
		if (applied != null || type != null) {
			if (conditionQuery.indexOf("where") == -1) {
				conditionQuery.append(" where ");
			}			
		}
			
				
		if (keyValue != null) {
			
			if (conditionQuery.indexOf("where") == -1) {
				conditionQuery.append(" where ");
			}	
			
			Set set = keyValue.entrySet();
			Iterator keyIter = set.iterator();
			
			while (keyIter.hasNext()) {
				Map.Entry<String, Object> entry = (Entry<String, Object>) keyIter
						.next();
				String name = entry.getKey();
				Object value = entry.getValue();

				conditionQuery.append(" n." + name + " = ? and ");
				params.add(value);
			}
		}
		if (fromDate != null && toDate == null) {
			conditionQuery.append("  n.status.processDate >= ?  and ");
			params.add(fromDate);
		}
		if (fromDate == null && toDate != null) {
			conditionQuery.append("  n.status.processDate <= ?  and ");
			params.add(toDate);
		}
		if (fromDate != null && toDate != null) {
			conditionQuery.append("  (n.status.processDate between ? and ?)  and ");
			params.add(fromDate);
			params.add(toDate);
		}

		if (applied != null) {
			if (applied == true) {
				conditionQuery.append(" n.status.processed = true and n.status.applied = false and ");
			}			
		}
		if (applied == null || applied == false) {
			conditionQuery.append(" n.status.applied = false and n.status.processed = true and ");
		}
		
		conditionQuery.append(" n.id = n.id ");
		countQuery.append(conditionQuery);
		findQuery.append(conditionQuery);
		
		try {
			session = HibernateUtil.getSessionFactory().openSession();
			tx = session.beginTransaction();
			
			allCount = FindUtil.calculateAllCount(session, countQuery.toString(), params);
			list = FindUtil.getEntitiesByPage(session, findQuery.toString(), params, start, count);
						
			iter = new PageIterator<Notice>(list, allCount, start, count);
			
			tx.commit();
		} catch (Exception e) {
			log.error(e.toString());
			if (tx != null) {
				tx.rollback();
			}
			
		} finally {
			if (session != null) {
				session.close();
			}
		}
		return iter;
	}
	
	public Notice findNoticeById(Long id) {
		Session session = null;
		Transaction tx = null;
		
		Notice notice = null;
		try {
			
			session = HibernateUtil.getSessionFactory().getCurrentSession();
			tx = session.beginTransaction();
			
			notice = (Notice) session.get(Notice.class, id);			
			
			tx.commit();
		} catch (Exception e) {
			log.error(e.getMessage());
			if (tx != null) {
				tx.rollback();
			}
			
		} finally {
			if (session != null) {
				if (session.isOpen()) {
					session.close();
				}
			}
		}
		return notice;
	}
}
